<template>
    <el-form-item class="async-select-grade" style="margin-bottom: 0!important;"><!-- 事件拦截 -->
        <el-select v-for="(data,index) in dataList" :key="index"
                   clearable
                   :value="values[index]"
                   @change="v => onSelectChange(index,v)"
                   @clear="clearChildren(index)"
                   :style="{width:~~(90/length) + '%'}">
            <!-- onSelectChange.bind(this,index)-->
            <el-option
                v-for="(item,index) in data" :key="index"
                :label="item[config.label]"
                :value="item[config.value]">
            </el-option>
        </el-select>
    </el-form-item>
</template>

<script>
    /**
     * # @param {object} config
     * - @param {object} api
     *  - @param {string} label 下拉框视图值
     *  - @param {string} value 下拉框model值
     *
     *  - @param {string} url
     *  - @param {string} dataField api返回数据的获取路径
     *  - @param {string} levelField 向服务端发送的数据，等级
     *  - @param {string} parentField 向服务端发送的数据，父级的值
     *  - @param {function} beforeAjax(payload,parent) 向服务端请求之前，用来自定义数据
     * */
    export default {
        inject: ['getDataPathByPath', 'utils', 'elFormItem', 'parseUrl'],
        props: {
            value: {
                default: null, // eg. ['l1','l2','l3'...'ln']
            },
            config: Object,
        },
        data() {
            this.isReview = false
            this.length = this.config.length || 0
            this.dataList = Array.from({length: this.length})
            return {
                values: [], // 与value不同，只有选到最后一级时，才会发射input事件
            }
        },
        methods: {
            getOptByValue(data, value) { // 一定存在的，不用判空
                const valueField = this.config.value
                return data.find(item => item[valueField] === value)
            },
            reset() {
                this.utils('clearValidate')
            },
            check() {
                this.utils('validate', this.values)
            },
            updateModel(values = this.values) {
                this.$emit('input', values)
            },
            clearChildren(index) {
                // 清空外部值
                this.updateModel([])
                this.reset()

                // 处理内部值
                this.values.splice(index, Infinity)

                // 处理内存中的数据
                index++
                const {dataList} = this
                for (; index < dataList.length; index++) {
                    delete dataList[index]
                }
                this.$forceUpdate()
            },
            onSelectChange(index, value) {
                if (!value) return // fix clearChildren()

                // 修复回显问题，例如第三个下拉框，value为123，这个选项之前有，但是现在被删掉了，那么回显就在这里停止
                if (this.isReview) {
                    const valueField = this.config.value
                    if (!this.dataList[index].find(item => item[valueField] === value)) return false
                }

                // 清空后面的
                this.values[index] = value
                this.clearChildren(index + 1)
                // this.$forceUpdate()

                // 选择的是最后一个
                if (index + 1 >= this.dataList.length) {
                    this.updateModel()
                    this.check()
                } else {
                    // 加载下一组select数据，并返回一个promise
                    return this.updateDataList(index + 1, this.getOptByValue(this.dataList[index], value))
                }
            },
            // 返回一个promise
            updateDataList(index, parent) {
                if (index >= this.dataList.length) return Promise.resolve()// 二次判断数组越界

                const {config, dataList} = this
                const payload = {
                    [config.api.levelField]: index + 1, // 默认从1开始
                    [config.api.parentField]: !parent ? '' : parent[config.value], // 默认携带父级的值
                }

                return Promise.resolve(config.api.beforeAjax instanceof Function ? config.api.beforeAjax(payload, parent || null) : payload)
                    .then($payload => {
                        if ($payload === false) return
                        $payload = $payload || payload // 不返回值，代指直接更改了引用
                        this.http[config.api.url.method](this.parseUrl(config.api.url), $payload).then(res => {
                            // 接口不规范，模拟接口数据（因为dataField设置的是 obj.list）
                            if (index === 0) {
                                res = {
                                    data: {
                                        obj: {
                                            list: res.data.obj.classify.list,
                                        }
                                    },
                                }
                            }
                            dataList[index] = this.getDataPathByPath(res.data, config.api.dataField)
                            this.$forceUpdate()
                        })
                    })
            }
        },
        async created() {
            if (!this.config.api) return this.dataList.length = 0 // 配置异常

            // 初始化第一个..
            await this.updateDataList(0)

            // 数据回显
            if (this.value) {
                this.isReview = true
                // 这里需要拷贝一份，不然要改很多逻辑
                const values = this.value.slice()
                for (let i = 0; i < values.length; i++) {
                    // 返回false，即回显失败，此组件的字段需要重新填写之后才能保存
                    if (await this.onSelectChange(i, values[i]) === false) {
                        // 回显失败
                        break
                    }
                }
                this.isReview = false
            }
        },
    }
</script>

<style lang="scss" scoped>
    .async-select-grade {
        margin-bottom: 0;
    }

    .el-select {
        display: inline-block;
        width: 180px; // 参考 number

        &:not(:last-child) {
            margin-right: 12px;
        }
    }
</style>
